package com.iraytek.rtsplib;

import android.util.Log;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

import pedro.rtsp.rtsp.Protocol;
import pedro.rtsp.rtsp.RtspSender;
import pedro.rtsp.utils.ConnectCheckerRtsp;

public class RtspClientThread extends Thread {
    private final String TAG = getClass().getSimpleName();
    private Socket socket;
    private ServerCommandManager commandsManager;
    private RtspSender rtspSender;
    private BufferedReader input;
    private BufferedWriter output;
    private boolean canSend;
    private int cSeq;

    public RtspClientThread(String serverIp, int port, Socket socket, ConnectCheckerRtsp connectCheckerRtsp) {
        this.socket = socket;
        rtspSender = new RtspSender(connectCheckerRtsp);
        commandsManager = new ServerCommandManager(serverIp, port, socket.getInetAddress().getHostAddress(), connectCheckerRtsp);
        try {
            input = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
            output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public RtspClientThread setMediaParams(boolean isStereo, int sampleRate, ByteBuffer sps, ByteBuffer pps, ByteBuffer vps) {
        commandsManager.setStereo(isStereo);
        commandsManager.setSampleRate(sampleRate);
        commandsManager.setVideoInfo(sps, pps, vps);
        return this;
    }

    @Override
    public void run() {
        super.run();
        while (!interrupted()) {
            try {
                String request = commandsManager.getRequest(input);//will block if clint has no request?
                if (BuildConfig.DEBUG) {
                    Log.w(TAG, "run: [request]" + request.length() + ";;" + request);
                }
                cSeq = commandsManager.getCSeq(request);
                if (cSeq == -1) { //If cSeq parsed fail send error to client
                    output.write(commandsManager.createError(500, cSeq));
                    output.flush();
                    continue;
                }
                String action = request.split("\n")[0];
                String response = commandsManager.createResponse(action, request, cSeq);
                if (BuildConfig.DEBUG) {
                    Log.w(TAG, "run: [response]" + response);
                }
                output.write(response);
                output.flush();
                if (action.toLowerCase().contains("play")) {
                    rtspSender.setSocketsInfo(commandsManager.getProtocol(), commandsManager.getVideoClientPorts(), commandsManager.getAudioClientPorts());
                    rtspSender.setVideoInfo(commandsManager.getSps(), commandsManager.getPps(), commandsManager.getVps());
                    rtspSender.setAudioInfo(commandsManager.getSampleRate());
                    rtspSender.setDataStream(socket.getOutputStream(), commandsManager.getClientIp());

                    if (commandsManager.getProtocol() == Protocol.UDP) {
                        ArrayList<Integer> videoPorts = commandsManager.getVideoPorts();
                        rtspSender.setVideoPorts(videoPorts.get(0), videoPorts.get(1));
                        ArrayList<Integer> audioPorts = commandsManager.getAudioPorts();
                        rtspSender.setAudioPorts(audioPorts.get(0), audioPorts.get(1));
                    }
                    rtspSender.start();
                    canSend = true;
                }
            } catch (SocketException e) {
                e.printStackTrace();
                break;//client disconnected
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void stopClient() {
        canSend = false;
        rtspSender.stop();
        interrupt();
        try {
            socket.shutdownInput();
            socket.shutdownOutput();
            socket.close();
            input.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public RtspSender getRtspSender() {
        return rtspSender;
    }

    public boolean canSend() {
        return canSend;
    }
}
